Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\runtime\src\message\payload\list.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::message::payload::list_base::impl_list_base;
30
use crate::message::{Error, FromBytes, FromBytesWithOffsets, Message, WriteTo};
31
use crate::util::ToUsize;
32
use std::io::Write;
33
use std::marker::PhantomData;
34
35
#[derive(Copy, Clone, Debug)]
36
pub struct List<B, T, Item> {
37
    data: B,
38
    len: usize,
39
    useless: PhantomData<T>,
40
    useless1: PhantomData<Item>,
41
}
42
43
impl<B, T, Item> List<B, T, Item> {
44
    /// Creates a list from raw parts.
45
    /// This function assumes that data has the number of items specified by len.
46
    /// A wrong length will simply cause an error (truncated) to be returned if the actual buffer
47
    /// has not enough bytes to contain all items.
48
    ///
49
    /// # Arguments
50
    ///
51
    /// * `data`: the data buffer.
52
    /// * `len`: the number of items to be read from the buffer.
53
    ///
54
    /// # Safety
55
    ///
56
    ///
57
    /// For all array types, (i.e. lists with fixed size items), a wrong length could result
58
    /// in UB where the array iterator, getter or setter attempts to slice out of bounds
59
    /// with a future optimization in release builds, currently it will result in a panic.
60
30
    pub fn from_raw_parts(data: B, len: usize) -> List<B, T, Item> {
61
30
        List {
62
30
            data,
63
30
            len,
64
30
            useless: PhantomData,
65
30
            useless1: PhantomData,
66
30
        }
67
30
    }
68
69
10
    pub fn new(data: B) -> List<B, T, Item> {
70
10
        List::from_raw_parts(data, 0)
71
10
    }
72
}
73
74
impl<B: AsRef<[u8]>, T, Item> List<B, T, Item> {
75
10
    pub fn to_ref<Item1>(&self) -> List<&[u8], T, Item1> {
76
10
        List::from_raw_parts(self.data.as_ref(), self.len)
77
10
    }
78
}
79
80
impl_list_base!(List);
81
82
impl<B: Write, T, I> List<B, T, I> {
83
22
    pub fn write_item<'a, Item: WriteTo<Input<'a> = Item>>(&mut self, item: &Item) -> Result<(), Error> {
84
22
        Item::write_to(item, &mut self.data)
?0
;
85
22
        self.len += 1;
86
22
        Ok(())
87
22
    }
88
89
0
    pub fn write_items<'a, Item: WriteTo<Input<'a> = Item>>(&mut self, items: &[Item]) -> Result<(), Error> {
90
0
        for item in items {
91
0
            self.write_item(item)?;
92
        }
93
0
        Ok(())
94
0
    }
95
}
96
97
impl<'a, T: FromBytes<'a, Output: ToUsize>, Item: FromBytes<'a, Output = Item>> FromBytes<'a>
98
    for List<&'a [u8], T, Item>
99
{
100
    type Output = List<&'a [u8], T, Item>;
101
102
4
    fn from_bytes(slice: &'a [u8]) -> Result<Message<Self::Output>, Error> {
103
4
        let msg = T::from_bytes(slice)
?0
;
104
4
        let control_size = msg.size();
105
4
        let len = msg.into_inner().to_usize();
106
4
        let data = &slice[control_size..];
107
4
        let mut total_size: usize = 0;
108
4
        for _ in 0..len {
109
8
            let msg = Item::from_bytes(&data[total_size..])
?0
;
110
8
            total_size += msg.size();
111
        }
112
4
        let data = &slice[control_size..control_size + total_size];
113
4
        Ok(Message::new(total_size + control_size, List::from_raw_parts(data, len)))
114
4
    }
115
}
116
117
impl<B: AsRef<[u8]>, T, Item> List<B, T, Item> {
118
10
    pub fn iter(&self) -> Iter<Item> {
119
10
        Iter {
120
10
            data: self.data.as_ref(),
121
10
            len: self.len,
122
10
            useless: PhantomData,
123
10
        }
124
10
    }
125
126
0
    pub fn iter_offsets(&self) -> IterOffsets<Item> {
127
0
        IterOffsets {
128
0
            data: self.data.as_ref(),
129
0
            len: self.len,
130
0
            useless: PhantomData,
131
0
        }
132
0
    }
133
}
134
135
pub struct Unsized<T, Item> {
136
    useless: PhantomData<T>,
137
    useless1: PhantomData<Item>,
138
}
139
140
impl<'a, T: FromBytes<'a, Output: ToUsize>, Item> FromBytes<'a> for Unsized<T, Item> {
141
    type Output = List<&'a [u8], T, Item>;
142
143
2
    fn from_bytes(slice: &'a [u8]) -> crate::message::Result<Message<Self::Output>> {
144
2
        let msg = T::from_bytes(slice)
?0
;
145
2
        let control_size = msg.size();
146
2
        let len = msg.into_inner().to_usize();
147
2
        let data = &slice[control_size..];
148
2
        Ok(Message::new(slice.len(), List::from_raw_parts(data, len)))
149
2
    }
150
}
151
152
pub struct Sized<B, T, S, Item> {
153
    useless: PhantomData<T>,
154
    useless1: PhantomData<S>,
155
    useless2: PhantomData<Item>,
156
    useless3: PhantomData<B>,
157
}
158
159
impl<'a, B, T: FromBytes<'a, Output: ToUsize>, S: FromBytes<'a, Output: ToUsize>, Item> FromBytes<'a>
160
    for Sized<B, T, S, Item>
161
{
162
    type Output = List<&'a [u8], T, Item>;
163
164
4
    fn from_bytes(slice: &'a [u8]) -> crate::message::Result<Message<Self::Output>> {
165
4
        let msg = T::from_bytes(slice)
?0
;
166
4
        let mut control_size = msg.size();
167
4
        let len = msg.into_inner().to_usize();
168
4
        let msg = S::from_bytes(&slice[control_size..])
?0
;
169
4
        control_size += msg.size();
170
4
        let total_size = control_size + msg.into_inner().to_usize();
171
4
        let data = &slice[control_size..total_size];
172
4
        Ok(Message::new(total_size, List::from_raw_parts(data, len)))
173
4
    }
174
}
175
176
impl<B: AsRef<[u8]>, T: WriteTo<Input<'static>: ToUsize>, S: WriteTo<Input<'static>: ToUsize>, Item> WriteTo
177
    for Sized<B, T, S, Item>
178
{
179
    type Input<'b> = List<B, T, Item>;
180
181
4
    fn write_to<W: Write>(input: &Self::Input<'_>, mut out: W) -> crate::message::Result<()> {
182
4
        T::write_to(&T::Input::from_usize(input.len), &mut out)
?0
;
183
4
        S::write_to(&S::Input::from_usize(input.data.as_ref().len()), &mut out)
?0
;
184
4
        out.write_all(input.data.as_ref())
?0
;
185
4
        Ok(())
186
4
    }
187
}
188
189
#[cfg(feature = "tokio")]
190
impl<
191
        B: AsRef<[u8]>,
192
        T: crate::message::WriteToAsync<Input<'static>: ToUsize>,
193
        S: crate::message::WriteToAsync<Input<'static>: ToUsize>,
194
        Item,
195
    > crate::message::WriteToAsync for Sized<B, T, S, Item>
196
{
197
0
    async fn write_to_async<W: tokio::io::AsyncWriteExt + Unpin>(
198
0
        input: &Self::Input<'_>,
199
0
        mut out: W,
200
0
    ) -> crate::message::Result<()> {
201
0
        T::write_to_async(&T::Input::from_usize(input.len), &mut out).await?;
202
0
        S::write_to_async(&S::Input::from_usize(input.data.as_ref().len()), &mut out).await?;
203
0
        out.write_all(input.data.as_ref()).await?;
204
0
        Ok(())
205
0
    }
206
}
207
208
pub struct Iter<'a, Item> {
209
    data: &'a [u8],
210
    len: usize,
211
    useless: PhantomData<Item>,
212
}
213
214
impl<'a, Item: FromBytes<'a, Output = Item>> Iterator for Iter<'a, Item> {
215
    type Item = crate::message::Result<Item>;
216
217
22
    fn next(&mut self) -> Option<Self::Item> {
218
22
        if self.len == 0 {
  Branch (218:12): [Folded - Ignored]
  Branch (218:12): [Folded - Ignored]
  Branch (218:12): [True: 0, False: 3]
  Branch (218:12): [True: 0, False: 8]
  Branch (218:12): [True: 0, False: 3]
  Branch (218:12): [True: 0, False: 8]
219
0
            return None;
220
22
        }
221
22
        let msg = match Item::from_bytes(self.data) {
222
0
            Err(e) => return Some(Err(e)),
223
22
            Ok(v) => v,
224
22
        };
225
22
        self.data = &self.data[msg.size()..];
226
22
        self.len -= 1;
227
22
        Some(Ok(msg.into_inner()))
228
22
    }
229
}
230
231
pub struct IterOffsets<'a, Item> {
232
    data: &'a [u8],
233
    len: usize,
234
    useless: PhantomData<Item>,
235
}
236
237
impl<'a, Item: FromBytes<'a, Output = Item> + FromBytesWithOffsets<'a>> Iterator for IterOffsets<'a, Item> {
238
    type Item = crate::message::Result<(Item, Item::Offsets)>;
239
240
0
    fn next(&mut self) -> Option<Self::Item> {
241
0
        if self.len == 0 {
  Branch (241:12): [Folded - Ignored]
  Branch (241:12): [Folded - Ignored]
242
0
            return None;
243
0
        }
244
0
        let msg = match Item::from_bytes_with_offsets(self.data) {
245
0
            Err(e) => return Some(Err(e)),
246
0
            Ok(v) => v,
247
0
        };
248
0
        self.data = &self.data[msg.size()..];
249
0
        self.len -= 1;
250
0
        Some(Ok(msg.into_inner()))
251
0
    }
252
}